#ifndef __RDB_H__
#define __RDB_H__

#ifdef __cplusplus
extern "C"
{
#endif

#include <stdint.h>
#include <unistd.h>

    typedef struct dictEntry
    {
        void *key;

        union
        {
            void *val;
            uint64_t u64;
            int64_t s64;
            double d;
        } v;
        struct dictEntry *next;
    } dictEntry;

    typedef struct dictType
    {
        unsigned int (*hashFunction )( const void *key );
        void *( *keyDup )( void *privdata, const void *key );
        void *( *valDup )( void *privdata, const void *obj );
        int (*keyCompare )( void *privdata, const void *key1, const void *key2 );
        void (*keyDestructor )( void *privdata, void *key );
        void (*valDestructor )( void *privdata, void *obj );
    } dictType;

    /* This is our hash table structure. Every dictionary has two of this as we
     * implement incremental rehashing, for the old to the new table. */
    typedef struct dictht
    {
        dictEntry **table;
        unsigned long size;
        unsigned long sizemask;
        unsigned long used;
    } dictht;

    typedef struct dict
    {
        dictType *type;
        void *privdata;
        dictht ht[2];
        long rehashidx; /* rehashing not in progress if rehashidx == -1 */
        int iterators; /* number of iterators currently running */
    } dict;

#define LRU_BITS 24
#define LRU_CLOCK_MAX ((1<<LRU_BITS)-1) /* Max value of obj->lru */
#define LRU_CLOCK_RESOLUTION 1000 /* LRU clock resolution in ms */

typedef struct redisObject
    {
        unsigned type : 4;
        unsigned encoding : 4;
        unsigned lru : LRU_BITS; /* lru time (relative to server.lruclock) */
        int refcount;
        void *ptr;
    } robj;

    typedef struct redisDb
    {
        struct dict *dict; /* The keyspace for this DB */
        struct dict *expires; /* Timeout of keys with a timeout set */
        struct evictionPoolEntry *eviction_pool; /* Eviction pool of keys */
        int id; /* Database ID */
        long long avg_ttl; /* Average TTL, just for stats */
    } redisDb;

    /* With multiplexing we need to take per-client state.
     * Clients are taken in a linked list. */
    typedef struct client
    {
        redisDb *db; /* Pointer to currently SELECTed DB. */
        int dictid; /* ID of the currently SELECTed DB. */
        int argc; /* Num of arguments of current command. */
        robj **argv; /* Arguments of current command. */
        struct redisCommand *cmd, *lastcmd; /* Last command executed. */

        void *resp;
        size_t *resp_len;
        size_t resp_pos;
        size_t limit;
    } client;


    typedef int *redisGetKeysProc ( struct redisCommand *cmd, robj **argv, int argc, int *numkeys );
    typedef int redisCommandProc ( client * );

    struct redisCommand
    {
        char *name;
        redisCommandProc *proc;
        int arity;
        char *sflags; /* Flags as string representation, one char per flag. */
        int flags; /* The actual flags, obtained from the 'sflags' field. */
        /* What keys should be loaded in background when calling this command? */
        redisGetKeysProc *getkeys_proc;
        int firstkey; /* The first argument that's a key (0 = no keys) */
        int lastkey; /* The last argument that's a key */
        int keystep; /* The step between first and last key */
        long long microseconds, calls;
    };

    typedef struct RdbCommand
    {
        void *cmd;
        size_t len;
    } RdbCommand;

    int rdb_init ( size_t mem_limit );
    client *createClient ( size_t limit );
    void freeClient ( client *c );
    int processInput ( client *c, int argc, RdbCommand *commands, size_t *resp_len, void *resp );

#ifdef __cplusplus
}
#endif

#endif  /*__RDB_H__*/
